const path = require("path");
const fs = require("fs");
const { SyncHook } = require('tapable');
const Complilation = require("./Complilation");

class Compiler {
  
  constructor(options){
      this.options= options;
      this.hooks = {
        initialize:new SyncHook(["arg"]),
        compile:new SyncHook(["arg"]),
        emit:new SyncHook(["arg"]),
        done:new SyncHook(["arg"])
      }
      this.outPutDir = this.options.output.path; // 输出目录
      this.bindHook();
  }
  
  /**
   * 绑定hook事件
   */
  bindHook(){
    const { plugins } =  this.options;
    plugins.forEach((plugin)=>{
       plugin.apply.call(plugin,this);
    })
    this.hooks.initialize.call(this.options); 
  }


  async run(){
    
    this.hooks.compile.call(this.options); // 开始构建之前触发的方法
    
    this.complilation = new Complilation(this.options,this); // 生成构建对象
    
    this.assets = await this.complilation.buildModule(); //开始执行编译
     
    this.hooks.emit.call(this.assets); // 输出静态资源到文件目录之前执行

    this.emit();

    this.hooks.done.call(); // 编译构建完成 

  }

  // 输出静态资源到文件目录
  emit(){
   
    if(!fs.existsSync(this.outPutDir)){ // 不存在就创建目录
      fs.mkdirSync(this.outPutDir);
    }

    const keys = Object.keys(this.assets);

    keys.forEach((filename)=>{

      const absolute_path = path.join(this.outPutDir,filename); // 打包后的绝对路径
         
      const dirs = filename.split(path.sep).filter((value)=>{
         return value !== "";
      })

      dirs.forEach((dir,index)=>{
        if(!dir.includes(".")){ // 目录处理
          const dist_file = path.resolve(this.outPutDir,dirs.slice(0,index+1).join(path.sep)); // 目标绝对路径
          if(!fs.existsSync(dist_file)){ // 不存在就创建目录
               fs.mkdirSync(dist_file,(err)=>{
                 err && console.log(err);
               });
          }
        }else { // 文件处理
            fs.writeFileSync(absolute_path,this.assets[filename]);    
        }
      })
    })

  }

}

module.exports = Compiler;
